package counter.com.baomidou.controller;


import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import counter.com.baomidou.entity.Loudongbuginfo;
import counter.com.baomidou.entity.Loudongscaninfo;
import counter.com.baomidou.entity.Loudongtargetinfo;
import counter.com.baomidou.service.ILoudongbuginfoService;
import counter.com.baomidou.service.ILoudongscaninfoService;
import counter.com.baomidou.service.ILoudongtargetinfoService;
import counter.com.common.MyTool;
import counter.com.common.Result;
import counter.com.common.StoreManager;
import counter.com.configuration.LoudongConfiguration;
import counter.com.connproperty.loudongjiance.*;
import counter.com.myservice.PollingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author jobob
 * @since 2020-10-07
 */
@RestController
@RequestMapping("/loudongscaninfo")
public class LoudongscaninfoController {
    @Autowired
    ILoudongscaninfoService scanService;

    @Autowired
    ILoudongtargetinfoService targetService;

    @Autowired
    ILoudongbuginfoService bugService;

    @Autowired
    LoudongConfiguration configuration;

    @Autowired
    PollingService pollingService;

    private HashSet<String> highLevelBugUrls;

    public static int TYPE_FULLSCAN = 0;
    public static int TYPE_HIGHRISK = 1;
    public static int TYPE_CROSS_SCRIPT = 2;
    public static int TYPE_SQL_INJECT = 3;
    public static int TYPE_PASSWORD_LACKNESS = 4;
    public static int TYPE_ONLY_CATCH = 5;

    public static int REPORT_NONE = 1;
    public static int REPORT_INFLUENCE = 2;
    public static int REPORT_DEVELOPER = 3;
    public static int REPORT_EXECUTE = 4;
    public static int REPORT_FAST = 5;


    public static int STATUS_STOP = 0;
    public static int STATUS_GOING = 1;
    public static int STATUS_FINISH = 2;
    //一个目标，最多生成的bug数
    private int MAX_BUG_LENGTH = 10;

    @PostMapping("/search")
    public Result search(@RequestBody ScanSearchProperty data) {
        LambdaQueryWrapper<Loudongscaninfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(true, Loudongscaninfo::getId);
        Page<Loudongscaninfo> page = new Page<>(data.getPage(), data.getPagesize());
        IPage<Loudongscaninfo> iPage = scanService.page(page, wrapper);
        List<Loudongscaninfo> records = iPage.getRecords();
        List<ScanSearchRespBag> resultList = convertRecords(records);
        ScanSearchRespBag property = new ScanSearchRespBag();
        property.setList(resultList);
        property.setTotal(iPage.getTotal());
        return Result.success(property);
    }

    private List<ScanSearchRespBag> convertRecords(List<Loudongscaninfo> records) {
        List<ScanSearchRespBag> list = new LinkedList<>();
        for (Loudongscaninfo info :
                records) {
            ScanSearchRespBag property = new ScanSearchRespBag();
            Integer targetId = info.getTid();
            Loudongtargetinfo target = targetService.getById(targetId);
            if (target != null) {
                property.setTarget(target);
                property.setCreatedtime(info.getCreatedtime());
                property.setReporttype(info.getReporttype());
                property.setStatus(info.getStatus());
                property.setType(info.getType());
                property.setId(info.getId());
                property.setProgress(info.getProgress());
                LambdaQueryWrapper<Loudongbuginfo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(Loudongbuginfo::getSid, info.getId()).eq(Loudongbuginfo::getLevel, LoudongbuginfoController.LEVEL_IGNORE);
                Integer hole_ignore = bugService.count(wrapper);
                wrapper.clear();
                wrapper.eq(Loudongbuginfo::getSid, info.getId()).eq(Loudongbuginfo::getLevel, LoudongbuginfoController.LEVEL_LOW);
                Integer hole_low = bugService.count(wrapper);
                wrapper.clear();
                wrapper.eq(Loudongbuginfo::getSid, info.getId()).eq(Loudongbuginfo::getLevel, LoudongbuginfoController.LEVEL_MEDIUM);
                Integer hole_medium = bugService.count(wrapper);
                wrapper.clear();
                wrapper.eq(Loudongbuginfo::getSid, info.getId()).eq(Loudongbuginfo::getLevel, LoudongbuginfoController.LEVEL_HIGH);
                Integer hole_high = bugService.count(wrapper);
                property.setHole_ignore(hole_ignore);
                property.setHole_low(hole_low);
                property.setHole_medium(hole_medium);
                property.setHole_high(hole_high);
                list.add(property);
            } else {
                //如果target不存在的话 本条扫描记录也会被删除掉
                scanService.removeById(info.getId());
            }
        }
        return list;
    }

    @PostMapping("/add")
    public Result add(@RequestBody ScanAddProperty data) {
        Integer[] tids = data.getTids();
        Boolean atLeastOneAdd = false;
        for (int i = 0; i < tids.length; i++) {
            Loudongtargetinfo target = targetService.getById(tids[i]);
            if (target != null) {
                Loudongscaninfo info = new Loudongscaninfo();
                ConvertPropertyToInfo(data, tids[i], info);
                info.setHosts(generateHosts());
                //扫描服务保存扫描信息
                scanService.save(info);
                //将扫描信息添加进入轮询服务
                pollingService.addScanIntoList(info);
                atLeastOneAdd = true;
            }
        }
        if (atLeastOneAdd) {
            return Result.success("开始扫描");
        } else {
            return Result.fail("请正确的选定扫描的目标");
        }
    }

    private String generateHosts() {
        StringBuilder result = new StringBuilder("[");
        int size = MyTool.getRandomInt(0, 3);
        for (int i = 0; i < size; i++) {
            FindHost host = new FindHost();
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < 3; j++) {
                sb.append(MyTool.getRandomInt(1, 255));
                sb.append(".");
            }
            sb.append(MyTool.getRandomInt(1, 255));
            host.setHost(sb.toString());
            host.setCreate(LocalDateTime.now());
            System.out.println("DEBUG");
            System.out.println(host);
            result.append(host.toString());
            if (i != size - 1) {
                result.append(",");
            }
        }
        result.append("]");
        return result.toString();
    }

    @PostMapping("/add_bybug")
    public Result add_bybug(@RequestBody ScanAddByBugProperty data) {
        Integer[] bids = data.getBids();
        boolean successFlag = false;
        int scanId = 0;
        for (int i = 0; i < bids.length; i++) {
            int bid = bids[i];
            Loudongbuginfo bug = bugService.getById(bid);
            if (bug == null) {
                continue;
            }
            Loudongscaninfo scanInfo = new Loudongscaninfo();
            scanInfo.setTid(bug.getTid());
            scanInfo.setProgress(100);
            scanInfo.setStatus(STATUS_FINISH);
            scanInfo.setCreatedtime(LocalDateTime.now());
            scanInfo.setType(TYPE_FULLSCAN);
            scanInfo.setReporttype(REPORT_NONE);
            if (scanService.save(scanInfo)) {
                bug.setSid(scanInfo.getId());
                //如果验证该Bug，那么Bug本身的状态变成Fixed
//                bug.setStatus(LoudongbuginfoController.STATUS_FIXED);
                if (bugService.save(bug)) {
                    if (!successFlag) {
                        successFlag = true;
                        scanId = scanInfo.getId();
                    }
                }
            }
        }
        if (successFlag)
            return Result.success(scanId);
        else
            return Result.fail("失败");
    }

    /**
     * 添加一些扫描必要的信息
     * 扫描的状态 被默认的设置为“进行中”
     * 扫描的进度 被默认的设置为0
     */
    private void ConvertPropertyToInfo(@RequestBody ScanAddProperty data, Integer tid, Loudongscaninfo info) {
        info.setReporttype(data.getReportType());
        info.setType(data.getType());
        info.setStatus(STATUS_GOING);
        info.setCreatedtime(LocalDateTime.now());
        info.setTid(tid);
        info.setProgress(0);
    }

    private Integer randomPickStatus() {
        if (Math.random() > 0.5) {
            return STATUS_GOING;
        } else {
            return STATUS_FINISH;
        }
    }

    @PostMapping("/delete")
    public Result delete(@RequestBody ScanDeleteProperty data) {
        if (scanService.removeByIds(Arrays.asList(data.getIds()))) {
            return Result.success("成功");
        } else {
            return Result.fail("失败");
        }
    }

    @PostMapping("/stop")
    public Result stop(@RequestBody ScanStopProperty data) {
        boolean successFlag = false;
        for (int i = 0; i < data.getIds().length; i++) {
            Integer id = data.getIds()[i];
            Loudongscaninfo info = scanService.getById(id);
            if (info == null) {
//                return Result.fail("未找到扫描信息");
                continue;
            }
            if (info.getStatus() == STATUS_FINISH) {
//                return Result.fail("已完成的扫描不可以停止");
                continue;
            } else if (info.getStatus() == STATUS_STOP) {
//                return Result.fail("已停止的扫描不可以停止");
                continue;
            }
            info.setStatus(STATUS_STOP);
            if (scanService.updateById(info)) {
                //成功
                successFlag = true;
            } else {
//                return Result.fail("停止扫描失败");
                continue;
            }
        }
        if (successFlag) {
            return Result.success("停止扫描成功");
        } else {
            return Result.fail("批量停止扫描失败(没有停止过至少一次扫描)");
        }
    }

    @PostMapping("/statistics")
    public Result statistics() {
        LambdaQueryWrapper<Loudongscaninfo> wrapper = new LambdaQueryWrapper<>();
        int totalCount = scanService.count();
        wrapper.eq(Loudongscaninfo::getStatus, STATUS_STOP);
        int stopCount = scanService.count(wrapper);
        wrapper.clear();
        wrapper.eq(Loudongscaninfo::getStatus, STATUS_GOING);
        int goingCount = scanService.count(wrapper);
        wrapper.clear();
        wrapper.eq(Loudongscaninfo::getStatus, STATUS_FINISH);
        int finishCount = scanService.count(wrapper);
        return Result.success(new ScanStatisticsProperty(totalCount, stopCount, goingCount, finishCount));
    }

    @PostMapping("/detail")
    public Result detail(@RequestBody ScanDetailProperty data) {
        Loudongscaninfo scanInfo = scanService.getById(data.getId());
        if (scanInfo == null) {
            return Result.fail("未找到扫描信息");
        }
        Integer targetId = scanInfo.getTid();
        Loudongtargetinfo target = targetService.getById(targetId);
        if (target == null) {
            return Result.fail("未找到目标信息");
        }
        LambdaQueryWrapper<Loudongbuginfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Loudongbuginfo::getSid, scanInfo.getId());
        List<Loudongbuginfo> bugList = bugService.list(wrapper);
        return Result.success(new ScanDetailRespProperty(scanInfo, target, bugList));
    }

}
